﻿using CKS2320.Common.Model;
using CKS2320.Common.Utils;
using CKS2320.Controller;
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
using Newtonsoft.Json;
using NPOI.SS.Formula.Functions;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace CKS2412.Controller.Action
{
    public class OEE_Service
    {
        #region 与主界面log日志方法绑定
        public delegate void AddLogHandler(string content, string source = "OEE服务");
        public static AddLogHandler AddLogEventHandler;
        #endregion

        SystemSettingModel sysModel = new SystemSettingModel();

        public OEE_Service()
        {

        }

        /// <summary>
        /// 心跳
        /// </summary>
        /// <param name="plc"></param>
        /// <returns></returns>
        public async Task Heartbeat(PLCController plc)
        {
            if (plc != null)
            {
                short? tick;
                while (plc.IsConnected())
                {
                    //发送心跳信号
                    //plc?.WriteInt(SignalAdrSetting.dbTotal_FromPc, SignalAdrSetting.WatchDog, 1);
                    //await Task.Delay(400);
                    tick = plc?.ReadIntOne(SignalAdrSetting.dbTotal, Convert.ToInt16(SignalAdrSetting.WatchDogToPC));
                    plc?.WriteInt(SignalAdrSetting.dbTotal_FromPc, SignalAdrSetting.WatchDog, (int)tick);                
                }
            }
        }

        /// <summary>
        /// 监听PLC数据
        /// </summary>
        /// <param name="plc">PLC对象</param>
        /// <returns></returns>
        public async Task PlcRunOEE(PLCController plc)
        {
            /*
             PLC专门设个DB块 用来交互OEE数据
             */
            if (plc != null)
            {
                int? deviceState;//设备状态
                int? deviceMode;//设备模式
                int? lastState = 0;//最后一次状态
                #region 开始时间、结束时间
                //DateTime totalTime = DateTime.Now;//总时间开始
                //DateTime stopTime = DateTime.Now;//停止时间开始
                //DateTime waitTime = DateTime.Now;//等待时间开始
                //DateTime faultTime = DateTime.Now;//错误时间开始
                DateTime? totalTime = null;//总时间结束
                DateTime? stopTime = null;//停止时间结束
                DateTime? waitTime = null;//等待时间结束
                DateTime? faultTime = null;//错误时间结束
                #endregion
                while (plc.IsConnected())
                {
                    await Task.Delay(500);
                    deviceState = plc?.ReadIntOne(SignalAdrSetting.dbTotal, Convert.ToInt32(SignalAdrSetting.DeviceState));
                    deviceMode = plc?.ReadIntOne(SignalAdrSetting.dbTotal, Convert.ToInt32(SignalAdrSetting.DeviceMode));
                    /*
                     运行状态：1=空闲，2=运行中，3=故障；4=待料中；
                     设备模式：1=空模式；2=手动；4=初始化；8=自动；16=自动模式下暂停;
                     ************良率、实际生产数量->PLC直接给************
                     */
                    if (deviceMode == 8 || deviceMode == 2/*8*/)//自动时间状态下才计时
                    {
                        if (deviceState == 16 && deviceState != lastState)//空闲
                        {
                            waitTime = DateTime.Now;
                            AddLogEventHandler?.Invoke("当前运行状态自动模式下暂停");
                        }
                        else if (deviceState == 2 && deviceState != lastState)//运行中
                        {
                            totalTime = DateTime.Now;
                            AddLogEventHandler?.Invoke("当前运行状态运行中");
                        }
                        else if (deviceState == 3 && deviceState != lastState)//故障
                        {
                            faultTime = DateTime.Now;
                            AddLogEventHandler?.Invoke("当前运行状态故障");
                        }
                        else if (deviceState == 4 && deviceState != lastState)//待料中
                        {
                            stopTime = DateTime.Now;
                            AddLogEventHandler?.Invoke("当前运行状态待料中");
                        }
                        if (deviceState != lastState)//互锁
                        {
                            AddLogEventHandler?.Invoke("进入OEE互锁条件");
                            if (lastState != 0)
                            {
                                AddLogEventHandler?.Invoke("OEE准备保存操作");
                                PerformanceRecordModel model = new PerformanceRecordModel()
                                {
                                    TotalRunTime = (float)(DateTime.Now - (totalTime == null ? DateTime.Now : totalTime))?.TotalMinutes,
                                    StopTime = (float)(DateTime.Now - (stopTime == null ? DateTime.Now : stopTime))?.TotalMinutes,
                                    WaitingTime = (float)(DateTime.Now - (waitTime == null ? DateTime.Now : waitTime))?.TotalMinutes,
                                    FaultTime = (float)(DateTime.Now - (faultTime == null ? DateTime.Now : faultTime))?.TotalMinutes
                                };
                                var dataSaveResult = SaveData(model);
                                await Task.Delay(1000);
                                if (dataSaveResult != null && dataSaveResult.Code == 1)
                                {
                                    switch (lastState)
                                    {
                                        case 16:
                                            waitTime = null;
                                            break;
                                        case 2:
                                            totalTime = null;
                                            break;
                                        case 3:
                                            faultTime = null;
                                            break;
                                        case 4:
                                            stopTime = null;
                                            break;
                                    }
                                    //上传成功
                                    AddLogEventHandler?.Invoke($"OEE数据保存成功，运行时间：{model.TotalRunTime}，停止时间：{model.StopTime}，等待时间：{model.WaitingTime}，故障时间：{model.FaultTime}");
                                }
                                else
                                {
                                    AddLogEventHandler?.Invoke("OEE数据保存失败，可能未与服务器建立连接");
                                }
                            }
                            lastState = deviceState;
                        }
                    }
                    else if (deviceMode == 2)
                    {
                        //Task.Delay(500);
                        //AddLogEventHandler?.Invoke("当前运行模式手动");
                    }
                    else
                    {

                    }
                    //GC.Collect();
                }
            }
        }
        /// <summary>
        /// 故障监听
        /// 1、新增故障 故障记录中不存在或存在但状态为正常 新增一条
        /// 2、故障状态变更  
        ///      1）读取PLC存在故障 记录中存在且状态是故障的 不做操作
        ///      2）读取PLC故障变更为正常 记录中存在且状态是故障的 将故障变为正常并记录故障时间
        /// </summary>
        /// <param name="plc"></param>
        /// <param name="data"></param>
        public async Task FaultMonitoring(PLCController plc, PLCDataModel data)
        {
            if (plc != null)
            {
                //Thread.Sleep(30000);
                await Task.Delay(30000);
                try
                {
                    //获取故障码表
                    string response = GetApiUtils.GetPostApi(data.Ip, sysModel.webApiUrl + "api/Equipmentfailure/GetEquipmentfailures?ip=" + data.Ip).GetAwaiter().GetResult();
                    var GetEquipmentfailureList = JsonConvert.DeserializeObject<List<EquipmentfailureModel>>(response);
                    AddLogEventHandler?.Invoke("故障监听连接返回1 :" + response);
                    AddLogEventHandler?.Invoke("开启故障监听", data.Ip);
                    while (plc.IsConnected())
                    {
                        await Task.Delay(1000);
                        //当前处于故障状态的记录
                        string historyStr = GetApiUtils.GetApi(sysModel.webApiUrl + "api/Equipmentfailure/GetFailureHistory?ip=" + data.Ip).GetAwaiter().GetResult();
                        //AddLogEventHandler?.Invoke("故障监听连接返回 2:" + historyStr);
                        var history = JsonConvert.DeserializeObject<List<EquipmentfailurehistoryModel>>(historyStr);
                        try
                        {
                            //读取PLC故障表
                            List<bool> faultList = plc?.ReadBitList(3001, 500, 128);
                            // Log4NetAppend("故障监听连接返回 :" + string.Join(",", faultList.Select(b => b ? "1" : "0")));
                            if (faultList != null)
                            {
                                #region 读取出来的故障记录
                                if (faultList.Select(p => p == true).Any())
                                {
                                    for (int i = 0; i < faultList.Count; i++)
                                    {
                                        if (faultList[i] == true)
                                        {
                                            //查看历史记录中是否存在正在故障的记录 不存在新增一条，存在不做操作
                                            var failureHistory = history?.FirstOrDefault(p => p.equipmentFailureInfo.FailureIndex == i);
                                            if (failureHistory == null)
                                            {
                                                var fauilure = GetEquipmentfailureList?.FirstOrDefault(p => p.FailureIndex == i);
                                                if (fauilure != null)
                                                {
                                                    AddLogEventHandler?.Invoke("记录正在故障的信息：" + historyStr);
                                                    InsertHistory(fauilure);
                                                    await Task.Delay(1000);
                                                }
                                            }
                                        }
                                    }
                                }
                                #endregion
                                #region 历史记录中正在故障的记录
                                if (history != null && history.Any())
                                {
                                    foreach (var item in history)
                                    {
                                        if (item.equipmentFailureInfo.FailureIndex != null)
                                        {
                                            //当前故障已变更为正常
                                            if (faultList[(int)item.equipmentFailureInfo.FailureIndex] == false)
                                            {
                                                AddLogEventHandler?.Invoke("当前故障已变更为正常：" + historyStr);
                                                GetApiUtils.GetApi(sysModel.webApiUrl + "api/Equipmentfailure/EditHistory?id=" + item.Id).GetAwaiter().GetResult();
                                                await Task.Delay(1000);
                                            }
                                        }
                                    }
                                }
                                #endregion
                            }
                        }
                        catch (Exception ex)
                        {
                            AddLogEventHandler?.Invoke("故障监听,发生错误 :" + ex.ToString());
                            AddLogEventHandler?.Invoke("故障监听,发生错误  " + ex.Message, data.Ip);
                        }
                    }
                    AddLogEventHandler?.Invoke("连接断开,故障监听结束", data.Ip);
                }
                catch (Exception ex)
                {
                    AddLogEventHandler?.Invoke("故障监听发生错误：  " + ex.Message, data.Ip);
                }
            }
        }

        /// <summary>
        /// 插入一条历史记录
        /// </summary>
        public void InsertHistory(EquipmentfailureModel fauilure)
        {
            EquipmentfailurehistoryModel insert = new()
            {
                FailureId = fauilure.Id,
                FaultType = true,
                StartTime = DateTime.Now,
                EndTime = null,
                TotalTime = null,
            };
            string requst = JsonConvert.SerializeObject(insert);
            GetApiUtils.GetPostApi(requst, sysModel.webApiUrl + "api/Equipmentfailure/InsertHistory").GetAwaiter().GetResult();
            //var history = JsonConvert.DeserializeObject<List<EquipmentfailurehistoryModel>>(historyStr);
        }
        /// <summary>
        /// 保存OEE数据
        /// </summary>
        /// <param name="plc">PLC对象</param>
        /// <returns></returns>
        public async Task SaveOEE(PLCController plc)
        {
            int numBytes = 4 * 4;//一个Real占4个字节  共4个数据：（1）总运行时间  （2）停止时间  （3）等待时间  （4）错误时间
            byte[] data = plc.ReadBytes(1002, 0, numBytes);//读取字节
            float[] dataRead = new float[numBytes / 4];
            for (int i = 0; i < dataRead.Length; i++)
            {
                byte[] floatData = new byte[4];
                //复制原始数据
                Array.Copy(data, i * 4, floatData, 0, 4);
                //反转字节顺序
                Array.Reverse(floatData);
                dataRead[i] = BitConverter.ToSingle(floatData, 0);
            }
            PerformanceRecordModel model = new PerformanceRecordModel()
            {
                TotalRunTime = dataRead[0],
                StopTime = dataRead[1],
                WaitingTime = dataRead[2],
                FaultTime = dataRead[3]
            };
            string request = JsonConvert.SerializeObject(model);
            string response = GetApiUtils.GetPostApi(request, sysModel.webApiUrl + "api/ThicknessDetection/AddPR").GetAwaiter().GetResult();//上传API
        }

        /// <summary>
        /// 保存数据
        /// </summary>
        /// <param name="data">数据</param>
        /// <returns></returns>
        public ResultReturn SaveData(dynamic data)
        {
            try
            {
                string request = JsonConvert.SerializeObject(data);
                AddLogEventHandler?.Invoke("正在保存OEE数据");
                string response = GetApiUtils.GetPostApi(request, sysModel.webApiUrl + "api/ThicknessDetection/AddPR").GetAwaiter().GetResult();
                return JsonConvert.DeserializeObject<ResultReturn>(response);
            }
            catch (Exception ex)
            {
                AddLogEventHandler?.Invoke("保存OEE数据时发生了异常：" + ex.Message);
            }
            return MessageInfoUtils.Fail();
        }

    }
}
